<template>
  <div class="va-df-input-control va-df-input-combo" :class="{'is-open': menuVisible}" :tabindex="disabled ? null : 0" :disabled="disabled" v-clickoutside="closeMenu" @click="toggleMenu" @keyup="quickKeyUp" @keydown="quickKeyDown">
    <div class="input-combo-label">{{formattedValue}}</div>
    <i class="right-icon va-icon-arrowdown"></i>
    <grid-panel v-show="menuVisible" :dataSource="dataSource" :is-loading="isLoading" :config="field" @selectionChange="selectionChange" ref="gridPanel"></grid-panel>
  </div>
</template>
<script>
  import _ from 'lodash'
  import clickoutside from '../../../libs/directives/clickoutside'
  import GridPanel from './GridPanel.vue'

  let setMenuState = function (vm, visible) {
    vm.menuVisible = visible
    if (!visible) {
      vm.$refs.gridPanel && vm.$refs.gridPanel.clearFocusState()
    }
  }

  export default {
    components: {GridPanel},
    directives: {clickoutside},
    props: {
      value: {},
      field: Object,
      disabled: Boolean,
      isLoading: Boolean,
      dataSource: {
        type: Array,
        default: []
      }
    },
    data () {
      let vm = this
      return {
        curSelectionNodes: [],
        menuVisible: false,
        lastValue: null,
        documentClickHandler (evt) {
          if (!vm.$el.contains(evt.target)) {
            setMenuState(vm, false)
          }
        }
      }
    },
    computed: {
      formattedValue () {
        if (this.field.comboRenderer) {
          if (!(this.field.comboRenderer instanceof Function)) {
            throw new Error('comboRenderer must be function...')
          }
          return this.field.comboRenderer(this.curSelectionNodes)
        }
        return _.chain(this.curSelectionNodes).map(node => {
          let val
          if (!_.isNil(this.field.comboDisplayRenderer)) {
            val = this.field.comboDisplayRenderer(node)
          } else if (!_.isNil(this.field.displayProp)) {
            val = _.get(node, this.field.displayProp)
          } else {
            val = node.$data
          }
          return val
        }).join(',').value()
      }
    },
    mounted () {
      this.$refs.gridPanel.setSelectedValues(
        this.field.comboMultiSelection ? this.value : this.value === undefined ? [] : [this.value]
      )
    },
    watch: {
      value: function (v, oldV) {
        if (_.isNil(v) && _.isNil(this.lastValue)) {
          return
        }
        if (this.field.comboMultiSelection) {
          if (!_.isEqual(_.sortBy(v), _.sortBy(this.lastValue))) {
            this.$refs.gridPanel.setSelectedValues(v)
          }
        } else {
          if (!_.isEqual(v, this.lastValue)) {
            this.$refs.gridPanel.setSelectedValues([v])
          }
        }
      }
    },
    methods: {
      selectionChange (nodes) {
        this.curSelectionNodes = nodes
        let val = null
        if (nodes.length === 0) {
          val = null
        } else {
          val = _.map(nodes, node => {
            if (!_.isNil(this.field.valueProp)) {
              return _.get(node.$data, this.field.valueProp)
            } else {
              return node.$data
            }
          })
          if (!this.field.comboMultiSelection) {
            val = _.head(val)
          }
        }
        this.lastValue = val
        this.$emit('input', val)

        if (!this.field.comboMultiSelection) {
          setMenuState(this, false)
        }
      },
      openMenu () {
        setMenuState(this, true)
      },
      closeMenu () {
        setMenuState(this, false)
      },
      toggleMenu (e) {
        if (!this.disabled && !this.$refs.gridPanel.$el.contains(e.target)) {
          setMenuState(this, !this.menuVisible)
        }
      },
      quickKeyUp (e) {
        if (this.disabled) {
          return
        }
        let keyCode = e.keyCode ? e.keyCode : e.which
        if (keyCode === 27) {
          e.preventDefault()
          e.stopPropagation()
        }
      },
      quickKeyDown (e) {
        if (this.disabled) {
          return
        }
        let keyCode = e.keyCode ? e.keyCode : e.which
        // tab or esc
        if (keyCode === 9 || keyCode === 27) {
          setMenuState(this, false)
          if (keyCode === 27) {
            e.preventDefault()
            e.stopPropagation()
          }
          return
        }
        // A all selection
        if (keyCode === 65) {
          this.$refs.gridPanel.quickKey(keyCode, e)

          e.preventDefault()
          e.stopPropagation()
          return false
        }
        if (e.altKey || e.ctrlKey || e.shiftKey) {
          return
        }
        if (keyCode === 13) {
          this.$emit('submit', e)
          return
        }
        switch (keyCode) {
          case 39: // right
            if (this.$refs.gridPanel.quickKey(keyCode) === false) {
              setMenuState(this, true)
            }
            break
          case 37: // left
            if (this.$refs.gridPanel.quickKey(keyCode) === false) {
              setMenuState(this, false)
            }
            break
          case 32: // blank space
          case 38: // up
          case 40: // down
            this.$refs.gridPanel.quickKey(keyCode)
            break
        }
        e.preventDefault()
        e.stopPropagation()
      }
    }
  }
</script>
